
<!DOCTYPE html>
<html lang="">


<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
  <meta name="theme-color" content="#202020"/>
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <script src="/js/busuanzi.pure.mini.js" async></script>
  
  
    <meta name="keywords" content="Java,Spring," />
  

  
    <meta name="description" content="一个专注一coding的网站。提供丰富编程知识，包括Spring、Java、EmberJS、SpringBoot等等技术。" />
  
  
  <link rel="icon" type="image/x-icon" href="/image/favicon.ico">
  <title>懒加载的几个疑问？？ [ Keep Coding ]</title>
  
    <!-- stylesheets list from config.yml -->
    
      <link rel="stylesheet" href="/css/pure-min.css">
    
      <link rel="stylesheet" href="/css/xoxo.css">
    
  
<meta name="generator" content="Hexo 5.0.2"><link rel="alternate" href="/atom.xml" title="Keep Coding" type="application/atom+xml">
</head>

<body>
  <div class="nav-container">
    <nav class="home-menu pure-menu pure-menu-horizontal">
  <a class="pure-menu-heading" href="/">
    <img class="avatar" src="/image/favicon.ico">
    <span class="title">Keep Coding</span>
  </a>

  <ul class="pure-menu-list clearfix">
      
          
            <li class="pure-menu-item"><a href="/" class="pure-menu-link">首页</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/archives" class="pure-menu-link">归档</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/tags" class="pure-menu-link">标签</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/search" class="pure-menu-link">搜索</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/about" class="pure-menu-link">关于</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/atom.xml" class="pure-menu-link">订阅</a></li>
          
      
  </ul>
   
</nav>
  </div>

  <div class="container" id="content-outer">
    <div class="inner" id="content-inner">
      <div class="post-container">
  <article class="post" id="post">
    <header class="post-header text-center">
      <h1 class="title">
        懒加载的几个疑问？？
      </h1>
      <span>
        
        <time class="time" datetime="2020-07-17T13:17:01.000Z">
        2020-07-17
      </time>
        
      </span>
      <span class="slash">/</span>
      <span class="post-meta">
      <span class="post-tags">
        <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Java/" rel="tag">Java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Spring/" rel="tag">Spring</a></li></ul>
      </span>
    </span>
      <span class="slash">/</span>
      <span class="read">
      <span id="busuanzi_value_page_pv"></span> 点击
    </span>
      <span class="slash">/</span>
      <span class="read">阅读耗时 12 分钟</span>
    </header>

    <div class="post-content">
      <h2 id="懒加载的几个疑问？？"><a href="#懒加载的几个疑问？？" class="headerlink" title="懒加载的几个疑问？？"></a>懒加载的几个疑问？？</h2><p>说明:<br>本篇是基于Spring5.x版本做的演示。不同的版本可能效果不一样，比如@Lazy注解在3.1版本是不支持在属性、构造方法、参数上使用的。</p>
<ul>
<li><p>对于使用了@Component注解的类如何统一做延迟加载，是否可以通过Bean定义的后置处理器<code>BeanDefinitionRegistryPostProcessor</code>做统一设置？</p>
<blockquote>
<p>答案是做不到，<code>BeanDefinitionRegistryPostProcessor</code>并未提供便利bean定义的方法，即使有也不好控制那些bean设置成懒加载</p>
</blockquote>
</li>
<li><p>BeanB依赖BeanA，当BeanB还未使用的时候BeanA是否会被加载？</p>
<blockquote>
<p>答案是BeanA会被加载，因为BeanB在设置属性的时候需要先加载BeanA。所以即使BeanB还未被使用BeanA也会被加载。</p>
</blockquote>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 20:46</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Lazy</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BeanOne</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BeanOne</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;\n\nbeanFactory开始加载BeanOne&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sayHelloBeanOne</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;调用BeanOne的方法&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 20:47</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Lazy</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BeanTwo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BeanTwo</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.printf(<span class="string">&quot;开始加载BeanTwo&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    BeanOne beanOne;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">invokeBeanOneMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;在BeanTwo里面调用BeanOne的方法&quot;</span>);</span><br><span class="line">        beanOne.sayHelloBeanOne();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 20:54</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;com.ubuntuvim.spring.lazyloading&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BeanLoadingConfig</span> </span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>验证如下。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.ubuntuvim.spring.lazyloading;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.AnnotationConfigApplicationContext;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 20:53</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LazyLoadingTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ApplicationContext ac = <span class="keyword">new</span> AnnotationConfigApplicationContext(BeanLoadingConfig.class);</span><br><span class="line">        BeanTwo beanTwo = (BeanTwo) ac.getBean(<span class="string">&quot;beanTwo&quot;</span>);</span><br><span class="line">        <span class="comment">// 未调beanTwo 的方法之后，不应该加载BeanOne。</span></span><br><span class="line">        System.out.println(<span class="string">&quot;未调beanTwo 的方法之后，不应该加载BeanOne（但事与愿违）&quot;</span>);</span><br><span class="line">        beanTwo.invokeBeanOneMethod();</span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">        执行结果：</span></span><br><span class="line"><span class="comment">            开始加载BeanTwo</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">            beanFactory开始加载BeanOne  ---- 因为BeanTwo里面引用了BeanOne，所以BeanOne在BeanTwo加载的时候也被加载了，不然无法初始化属性。</span></span><br><span class="line"><span class="comment">            未调beanTwo 的方法之后，不应该加载BeanOne</span></span><br><span class="line"><span class="comment">            在BeanTwo里面调用BeanOne的方法</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 只使用BeanOne时，BeanTwo不会被加载</span></span><br><span class="line">        BeanOne beanOne = (BeanOne) ac.getBean(<span class="string">&quot;beanOne&quot;</span>);</span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">        执行结果：</span></span><br><span class="line"><span class="comment">            beanFactory开始加载BeanOne</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li>对于实现了Spring初始化方法的bean，设置<code>lazy-init</code>属性为<code>true</code>是否能起到延迟加载的效果？？</li>
</ul>
<blockquote>
<p>实现了<code>InitializingBean</code>的bean本身使用了<code>@Lazy</code>注解是可以延迟加载的。但是如果是父类实现了<code>InitializingBean</code>的方法，但是没有使用<code>@Lazy</code>注解，而是在子类中使用了<code>@Lazy</code>注解，那么父类的spring初始化方法是会被执行的，<code>@Lazy</code>注解只是对当前类起效果，并不能控制父类的懒加载。</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 21:26</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Lazy</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyInitializingBean</span> <span class="keyword">implements</span> <span class="title">InitializingBean</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;实现了InitializingBean的afterPropertiesSet()方法被调用了&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 未使用<span class="doctag">@Lazy</span>注解，但是子类使用<span class="doctag">@Lazy</span>注解，是否可以实现延迟加载呢？答案是不行，<span class="doctag">@Lazy</span>只对当前类起效果。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 21:26</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyInitializingBeanNoLazy</span> <span class="keyword">implements</span> <span class="title">InitializingBean</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyInitializingBeanNoLazy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyInitializingBeanNoLazy被加载了&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;===== MyInitializingBeanNoLazy的afterPropertiesSet()方法被调用了 =====&quot;</span>);</span><br><span class="line">        <span class="comment">// 即使子类使用了@Lazy注解父类的afterPropertiesSet方法也会被调用的。</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 本类使用了延迟加载注解，并不能对父类的加载起作用</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 21:35</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Lazy</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyInitializingBeanSubClass</span> <span class="keyword">extends</span> <span class="title">MyInitializingBeanNoLazy</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyInitializingBeanSubClass</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyInitializingBeanNoLazy的子类使用@Lazy注解，子类被加载了&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>执行效果，MyInitializingBeanNoLazy一开始就被加载了。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">MyInitializingBeanNoLazy被加载了</span><br><span class="line">&#x3D;&#x3D;&#x3D;&#x3D;&#x3D; MyInitializingBeanNoLazy的afterPropertiesSet()方法被调用了 &#x3D;&#x3D;&#x3D;&#x3D;&#x3D;</span><br><span class="line">开始加载BeanTwo未调beanTwo 的方法之后，不应该加载BeanOne（但事与愿违）</span><br><span class="line">在BeanTwo里面调用BeanOne的方法</span><br><span class="line">beanFactory开始加载BeanOne</span><br><span class="line">调用BeanOne的方法</span><br><span class="line">在未使用MyInitializingBean之前，如果bean使用了@Lazy注解，即使这个bean实现了InitializingBean的接口也不会被加载</span><br><span class="line">实现了InitializingBean的afterPropertiesSet()方法被调用了</span><br><span class="line"></span><br><span class="line">BUILD SUCCESSFUL in 9s</span><br><span class="line">80 actionable tasks: 2 executed, 78 up-to-date</span><br><span class="line">21:42:01: Task execution finished &#39;LazyLoadingTest.main()&#39;.</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li>使用XML方式定义使用Spring初始化方法的类是否可以实现懒加载？？</li>
</ul>
<p>定义一个实现了Spring初始化方法的Bean。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 未使用<span class="doctag">@Lazy</span>注解，但是子类使用<span class="doctag">@Lazy</span>注解，是否可以实现延迟加载呢？答案是不行，<span class="doctag">@Lazy</span>只对当前类起效果。</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * xml方式定义bean可以实现懒加载，因为不是继承方式，这种方式就是别名的方式，MyInitializingBeanSubClassUseLazy instanceOf MyInitializingBeanNoLazy =&gt; true</span></span><br><span class="line"><span class="comment"> * &lt;bean name=&quot;myInitializingBeanSubClassUseLazy&quot; class=&quot;com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazy&quot; lazy-init=&quot;true&quot;&gt;</span></span><br><span class="line"><span class="comment"> * &lt;property name=&quot;name&quot; value=&quot;使用了Lazy-init=true，父类的afterPropertiesSet方法也会被调用&quot; /&gt;</span></span><br><span class="line"><span class="comment"> * &lt;/bean&gt;</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 但是，当另外一个类BeanA里面引用了myInitializingBeanSubClassUseLazy，也不能实现懒加载，因为BeanA在设置属性的时候会先初始化myInitializingBeanSubClassUseLazy。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 21:26</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyInitializingBeanNoLazy</span> <span class="keyword">implements</span> <span class="title">InitializingBean</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyInitializingBeanNoLazy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="keyword">this</span>.getClass().getName() + <span class="string">&quot;被加载了&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;===== MyInitializingBeanNoLazy的afterPropertiesSet()方法被调用了 =====&quot;</span>);</span><br><span class="line">        <span class="comment">// 即使子类使用了@Lazy注解父类的afterPropertiesSet方法也会被调用的。</span></span><br><span class="line">        System.out.println(<span class="string">&quot;name的值是：&quot;</span> + <span class="keyword">this</span>.name + <span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过xml注入</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    String name;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans</span></span></span><br><span class="line"><span class="tag"><span class="string">       http://www.springframework.org/schema/beans/spring-beans.xsd</span></span></span><br><span class="line"><span class="tag"><span class="string">       http://www.springframework.org/schema/context</span></span></span><br><span class="line"><span class="tag"><span class="string">       http://www.springframework.org/schema/context/spring-context.xsd &quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.ubuntuvim.spring.lazyloading&quot;</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 使用了lazy-init可以做到懒加载类本身懒加载，就相当于在com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazy上使用@Lazy注解 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">&quot;myInitializingBeanSubClassUseLazy&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazy&quot;</span> <span class="attr">lazy-init</span>=<span class="string">&quot;true&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;使用了Lazy-init=true&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 使用了lazy-init可以做到懒加载类本身懒加载，就相当于在com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazy上使用@Lazy注解</span></span><br><span class="line"><span class="comment">     但是如果有另外一个类引用了myInitializingBeanSubClassUseLazyByOtherRef，那么即使引用的类设置了懒加载，myInitializingBeanSubClassUseLazyByOtherRef也会被加载</span></span><br><span class="line"><span class="comment">     因为引用类在初始化设置属性的时候会先初始化依赖的属性。</span></span><br><span class="line"><span class="comment">     有一种方式可以做到懒加载，就是在引用的属性上同时使用@Lazy注解。</span></span><br><span class="line"><span class="comment">     @Resource</span></span><br><span class="line"><span class="comment">     @Lazy</span></span><br><span class="line"><span class="comment">     MyInitializingBeanNoLazy myInitializingBeanSubClassUseLazyByOtherRef;</span></span><br><span class="line"><span class="comment">     --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">&quot;myInitializingBeanSubClassUseLazyByOtherRef&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazy&quot;</span> <span class="attr">lazy-init</span>=<span class="string">&quot;true&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;使用了Lazy-init=true，但是被另外的类引用了。也会被加载。如果在引用的属性上使用了@Lazy注解，那么也可以实现懒加载！&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">&quot;myInitializingBeanSubClassNotUseLazy&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazy&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;未使用lazy-init=false&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>验证结果</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.ubuntuvim.spring.lazyloading;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 22:03</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LazyLoadingXmlContextTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ApplicationContext ac = <span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="string">&quot;classpath*:lazy-loading-test.xml&quot;</span>);</span><br><span class="line">        <span class="comment">// 容器加载，MyInitializingBeanSubClassUseLazy和MyInitializingBeanSubClassNotUseLazy都交给容器管理。</span></span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">        执行结果可见，afterPropertiesSet()方法被调用了。</span></span><br><span class="line"><span class="comment">        MyInitializingBeanNoLazy被加载了，name =</span></span><br><span class="line"><span class="comment">        ===== MyInitializingBeanNoLazy的afterPropertiesSet()方法被调用了 =====</span></span><br><span class="line"><span class="comment">        name的值是：未使用lazy-init=true</span></span><br><span class="line"><span class="comment">        */</span></span><br><span class="line"><span class="comment">//        MyInitializingBeanNoLazy myInitializingBeanNoLazy = (MyInitializingBeanNoLazy) ac.getBean(&quot;myInitializingBeanSubClassUseLazy&quot;);</span></span><br><span class="line"><span class="comment">//        System.out.println(myInitializingBeanNoLazy instanceof MyInitializingBeanNoLazy);</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 即使没用使用BeanRef，但是由于在类中引用了myInitializingBeanSubClassUseLazyByOtherRef，</span></span><br><span class="line">        <span class="comment">// 即使myInitializingBeanSubClassUseLazyByOtherRef定义成lazy-init=true也会被加载。</span></span><br><span class="line">        BeanRef beanRef = (BeanRef) ac.getBean(<span class="string">&quot;beanRef&quot;</span>);</span><br><span class="line">        <span class="comment">// 在没用使用到myInitializingBeanSubClassUseLazyByOtherRef属性之前，不会加载这个属性类。</span></span><br><span class="line">        System.out.println(<span class="string">&quot;\n\n没有使用到BeanRef中引用的属性，属性类不会被加载&quot;</span>);</span><br><span class="line">        <span class="comment">// 使用myInitializingBeanSubClassUseLazyByOtherRef</span></span><br><span class="line">        beanRef.useProp();</span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">        执行结果：</span></span><br><span class="line"><span class="comment">        开始使用属性myInitializingBeanSubClassUseLazyByOtherRef</span></span><br><span class="line"><span class="comment">        MyInitializingBeanNoLazy被加载了sun.misc.Launcher$AppClassLoader@2a139a55    --&gt; 属性类被加载</span></span><br><span class="line"><span class="comment">        ===== MyInitializingBeanNoLazy的afterPropertiesSet()方法被调用了 =====        --&gt; 属性类的初始化方法被调用</span></span><br><span class="line"><span class="comment">        name的值是：使用了Lazy-init=true，但是被另外的类引用了。也会被加载。                    --&gt; BeanRef本身被加载</span></span><br><span class="line"><span class="comment">        使用属性并调用其方法完毕                                                        --&gt; 调用BeanRef方法，触发加载</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;执行完毕&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>如果引用的类属性上也使用了<code>@Lazy</code>注解，那么被引用的类也是可以实现懒加载的，即使是被引用的类实现了Spring的初始化方法也可以实现。比如例子中的<code>BeanRef</code>这个类，在类中引用的属性上也使用了<code>@Lazy</code>注解，可以实现懒加载。</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Resource</span></span><br><span class="line"><span class="meta">@Lazy</span></span><br><span class="line">MyInitializingBeanNoLazy myInitializingBeanSubClassUseLazyByOtherRef;</span><br></pre></td></tr></table></figure>


<ul>
<li>使用XML方式定义使用Spring初始化方法的类<code>InitializingBean</code>，并且类实现了<code>FactoryBean</code>接口是否可以实现懒加载？？</li>
</ul>
<blockquote>
<p> 答案是做不到，由于在afterPropertiesSet方法中调用了工厂bean的生成方法，使得当前类必须被实例化，否则无法实现工厂bean功能无法创建有工厂bean创建的对象。无论getObject方法做什么操作本类都会被实例化。<br>即使在类上使用@Lazy注解，在getObject方法上使用@Lazy注解，在afterPropertiesSet方法上使用@Lazy注解都是无效的。<br>因为FactoryBean是用于向容器注册bean的，它自己必须先实例化了才能执行getObject，才能向容器注册bean。<br>简单讲，只要是实现了FactoryBean的类都无法做到懒加载。<br>需要注意的是通过FactoryBean.getObject()方法创建的bean不会在容器启动的时候就实例化。当创建的bean用到的时候才实例化，也就是说同FactoryBean.getObject()方法创建的bean默认是懒加载的,但是一个同时实现了InitializingBean, FactoryBean这两个接口，并且在afterPropertiesSet方法里再调用了getObject()方法就可以做到在容器启动的时候就做初始化，因为实现FactoryBean接口的类会在容器启动的时候实例化，由于被实例化了所以afterPropertiesSet方法就会被容器自动调用。<br>组合起来就实现了实时加载。</p>
</blockquote>
<p>例子如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.ubuntuvim.spring.lazyloading;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.FactoryBean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.InitializingBean;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 同时实现了Bean初始化方法和FactoryBean方法的类，是否可以做到懒加载？？</span></span><br><span class="line"><span class="comment"> * 答案是做不到，由于在afterPropertiesSet方法中调用了工厂bean的生成方法，使得当前类必须被实例化，否则无法实现工厂bean功能无法创建有工厂bean创建的对象。</span></span><br><span class="line"><span class="comment"> * 无论getObject方法做什么操作本类都会被实例化。</span></span><br><span class="line"><span class="comment"> * 即使在类上使用<span class="doctag">@Lazy</span>注解，在getObject方法上使用<span class="doctag">@Lazy</span>注解，在afterPropertiesSet方法上使用<span class="doctag">@Lazy</span>注解都是无效的。</span></span><br><span class="line"><span class="comment"> * 因为FactoryBean是用于向容器注册bean的，它自己必须先实例化了才能执行getObject，才能向容器注册bean。</span></span><br><span class="line"><span class="comment"> * 简单讲，只要是实现了FactoryBean的类都无法做到懒加载。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 需要注意的是通过FactoryBean.getObject()方法创建的bean不会在容器启动的时候就实例化。当创建的bean用到的时候才实例化，</span></span><br><span class="line"><span class="comment"> * 也就是说同FactoryBean.getObject()方法创建的bean默认是懒加载的</span></span><br><span class="line"><span class="comment"> * 但是一个同时实现了InitializingBean, FactoryBean这两个接口，并且在afterPropertiesSet方法里再调用了getObject()方法</span></span><br><span class="line"><span class="comment"> * 就可以做到在容器启动的时候就做初始化，因为实现FactoryBean接口的类会在容器启动的时候实例化，由于被实例化了所以afterPropertiesSet方法就会被容器自动调用。</span></span><br><span class="line"><span class="comment"> * 组合起来就实现了实时加载。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: ubuntuvim</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/7/17 23:58</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">//@Lazy  // 无效</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyInitializingBeanNoLazyAndBeanFactoryImpl</span> <span class="keyword">implements</span> <span class="title">InitializingBean</span>, <span class="title">FactoryBean</span>&lt;<span class="title">InitFromGetObjectMethodBean</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyInitializingBeanNoLazyAndBeanFactoryImpl</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="keyword">this</span>.getClass().getName() + <span class="string">&quot;被加载了&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//    @Lazy  // 无效</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="keyword">this</span>.getClass().getName() + <span class="string">&quot; afterPropertiesSet()方法被调用了 =====&quot;</span>);</span><br><span class="line">        <span class="comment">// 即使子类使用了@Lazy注解父类的afterPropertiesSet方法也会被调用的。</span></span><br><span class="line">        <span class="comment">// 但是如果本类被另外一个类引用了，但是在引用的属性上也使用了@Lazy注解，那么本类可是懒加载</span></span><br><span class="line">        System.out.println(<span class="string">&quot;name的值是：&quot;</span> + <span class="keyword">this</span>.name + <span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        getObject();  <span class="comment">// 即使不调用getObject方法也做不到懒加载，容器在启动的时候就会实例化当前类</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过xml注入</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    String name;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 无论这个方法做什么操作都会在容器启动的时候初始化，无法做到延迟加载</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="comment">//    @Lazy  // 无效</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> InitFromGetObjectMethodBean <span class="title">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="keyword">this</span>.getClass().getName() + <span class="string">&quot;的getObject方法被调用&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> InitFromGetObjectMethodBean();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; getObjectType() &#123;</span><br><span class="line">        <span class="keyword">return</span> InitFromGetObjectMethodBean.class;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isSingleton</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans</span></span></span><br><span class="line"><span class="tag"><span class="string">       http://www.springframework.org/schema/beans/spring-beans.xsd</span></span></span><br><span class="line"><span class="tag"><span class="string">       http://www.springframework.org/schema/context</span></span></span><br><span class="line"><span class="tag"><span class="string">       http://www.springframework.org/schema/context/spring-context.xsd &quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.ubuntuvim.spring.lazyloading&quot;</span> /&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    在没有使用过bean之前，通过FactoryBean.getObject创建的bean不会直接在容器启动的时候实例化。比如InitBeanFromGetObject2不会在容器启动的时候实例化。</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">name</span>=<span class="string">&quot;myInitializingBeanNoLazyAndBeanFactoryImplByOtherRef&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazyAndBeanFactoryImpl&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">lazy-init</span>=<span class="string">&quot;true&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;我是一个同时实现了Bean初始化方法和FactoryBean方法的类，我即使被定义为lazy-init=true也会在启动时被实例化。</span></span></span><br><span class="line"><span class="tag"><span class="string">        因为FactoryBean实现类必须先被实例化才能调用getObject方法向容器注册bean&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>即使没有测试类中调用这个类，容器启动时也会加载，验证结果如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">使用属性并调用其方法完毕</span><br><span class="line"></span><br><span class="line">在未使用InitFromGetObjectMethodBean之前，这个InitFromGetObjectMethodBean类不会在容器启动的时候实例化</span><br><span class="line">com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazyAndBeanFactoryImpl afterPropertiesSet()方法被调用了 &#x3D;&#x3D;&#x3D;&#x3D;&#x3D;</span><br><span class="line">name的值是：我是一个同时实现了Bean初始化方法和FactoryBean方法的类，我即使被定义为lazy-init&#x3D;true也会在启动时被实例化。   因为FactoryBean实现类必须先被实例化才能调用getObject方法向容器注册bean</span><br><span class="line"></span><br><span class="line">com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazyAndBeanFactoryImpl的getObject方法被调用</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">com.ubuntuvim.spring.lazyloading.InitFromGetObjectMethodBean这个bean是通过FactoryBean.getObject方法创建的</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">com.ubuntuvim.spring.lazyloading.MyInitializingBeanNoLazyAndBeanFactoryImpl的getObject方法被调用</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">com.ubuntuvim.spring.lazyloading.InitFromGetObjectMethodBean这个bean是通过FactoryBean.getObject方法创建的</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">com.ubuntuvim.spring.lazyloading.InitFromGetObjectMethodBean@64cd705f</span><br><span class="line">执行完毕</span><br><span class="line"></span><br><span class="line">BUILD SUCCESSFUL in 20s</span><br><span class="line">80 actionable tasks: 1 executed, 79 up-to-date</span><br><span class="line">02:53:15: Task execution finished &#39;LazyLoadingXmlContextTest.main()&#39;.</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>按照XML的配置顺序，这个类在最后面被加载了。</p>
<p>更深入的原因我们从Spring源码层级分析。按照如下流程找到方法，</p>
<pre class="mermaid">graph TD;
    ClassPathXmlApplicationContext --> AbstractApplicationContext.refresh;
    AbstractApplicationContext.refresh --> finishBeanFactoryInitialization方法;
    finishBeanFactoryInitialization方法 --> beanFactory.preInstantiateSingletons方法;
    beanFactory.preInstantiateSingletons方法 --> DefaultListableBeanFactory.preInstantiateSingletons方法;</pre>

<p>DefaultListableBeanFactory.preInstantiateSingletons方法是最后的核心方法。这个方法内部实例化了实现FactoryBean的类并调用getObject方法向容器注册bean，并且这个方法只有非懒加载的bean能进入到这里。。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 实例化所有除了Spring内部的单例（懒加载的除外）</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">preInstantiateSingletons</span><span class="params">()</span> <span class="keyword">throws</span> BeansException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (logger.isTraceEnabled()) &#123;</span><br><span class="line">        logger.trace(<span class="string">&quot;Pre-instantiating singletons in &quot;</span> + <span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Iterate over a copy to allow for init methods which in turn register new bean definitions.</span></span><br><span class="line">    <span class="comment">// While this may not be part of the regular factory bootstrap, it does otherwise work fine.</span></span><br><span class="line">    <span class="comment">// 创建BeanDefinitionName副本，用于后续遍历，以允许init等方法注册新的bean定义</span></span><br><span class="line">    List&lt;String&gt; beanNames = <span class="keyword">new</span> ArrayList&lt;&gt;(<span class="keyword">this</span>.beanDefinitionNames);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Trigger initialization of all non-lazy singleton beans...</span></span><br><span class="line">    <span class="comment">// 遍历所有的beanName，通过beanName获取到对应的bean实例</span></span><br><span class="line">    <span class="keyword">for</span> (String beanName : beanNames) &#123;</span><br><span class="line">        <span class="comment">// 根据bean名称拿到bean定义</span></span><br><span class="line">        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);</span><br><span class="line">        <span class="comment">// bean定义非抽象类，是单例，非懒加载</span></span><br><span class="line">        <span class="keyword">if</span> (!bd.isAbstract() &amp;&amp; bd.isSingleton() &amp;&amp; !bd.isLazyInit()) &#123;</span><br><span class="line">            <span class="comment">// 判断是否是FactoryBean</span></span><br><span class="line">            <span class="comment">// Spring有两种类型的Bean，一种普通Bean，一种是工厂Bean即FactoryBean，FactoryBean和普通Bean不同，</span></span><br><span class="line">            <span class="comment">// 它返回的对象不是一个指定类型的对象，而是根据FactoryBean&lt;T&gt;.geteObject()返回对象，返回的对象就是T类型的，</span></span><br><span class="line">            <span class="comment">// 创建出来的对象是否为单例是根据Bean定义中的isSingleton属性决定的（默认是单例）</span></span><br><span class="line">            <span class="keyword">if</span> (isFactoryBean(beanName)) &#123;</span><br><span class="line">                <span class="comment">// 通过getBean(&amp;beanName)拿到是FactoryBean本身，FACTORY_BEAN_PREFIX=&amp;</span></span><br><span class="line">                <span class="comment">// 通过getBean(beanName)拿到的是FactoryBean创建的bean实例</span></span><br><span class="line">                <span class="comment">// 比如  MyInitializingBeanNoLazyAndBeanFactoryImpl implements FactoryBean&lt;Object&gt;</span></span><br><span class="line">                <span class="comment">// 拿到的就是myInitializingBeanNoLazyAndBeanFactoryImpl这个bean实例。</span></span><br><span class="line">                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);</span><br><span class="line">                <span class="keyword">if</span> (bean <span class="keyword">instanceof</span> FactoryBean) &#123;</span><br><span class="line">                    <span class="keyword">final</span> FactoryBean&lt;?&gt; factory = (FactoryBean&lt;?&gt;) bean;</span><br><span class="line">                    <span class="comment">// 判断bean是否需要急切初始化，实现了FactoryBean的类isEagerInit都是false，</span></span><br><span class="line">                    <span class="comment">// 只有SmartFactoryBean的实现类可以控制这个属性值，但是这个接口是提供给Spring框架本身内部使用的不建议开发者使用</span></span><br><span class="line">                    <span class="keyword">boolean</span> isEagerInit;</span><br><span class="line">                    <span class="keyword">if</span> (System.getSecurityManager() != <span class="keyword">null</span> &amp;&amp; factory <span class="keyword">instanceof</span> SmartFactoryBean) &#123;</span><br><span class="line">                        isEagerInit = AccessController.doPrivileged((PrivilegedAction&lt;Boolean&gt;)</span><br><span class="line">                                        ((SmartFactoryBean&lt;?&gt;) factory)::isEagerInit,</span><br><span class="line">                                getAccessControlContext());</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">else</span> &#123;</span><br><span class="line">                        isEagerInit = (factory <span class="keyword">instanceof</span> SmartFactoryBean &amp;&amp;</span><br><span class="line">                                ((SmartFactoryBean&lt;?&gt;) factory).isEagerInit());</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">if</span> (isEagerInit) &#123;</span><br><span class="line">                        <span class="comment">// 通过beanName获取bean实例</span></span><br><span class="line">                        getBean(beanName);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 普通的bean直接通过beanName获取bean实例</span></span><br><span class="line">                getBean(beanName);  <span class="comment">// 转到AbstractBeanFactory</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//  方面后面的代码省略。。。。</span></span><br></pre></td></tr></table></figure>

<p>经过上述代码之后， MyInitializingBeanNoLazyAndBeanFactoryImpl就被实例化好了。但是也只是FactoryBean实现类本身被实例化了，还没真正调用getObject方法注册bean，只有在使用到被注册的bean的时候才会执行getObject方法，也就是说通过FactoryBean.getObject()方法创建的bean默认是懒加载的。</p>

    </div>

      
    <div class="post-nav">
      <div class="post-nav-item post-nav-next">
        
          <span>〈 </span>
          <a href="/2020/05/04/Spring/Spring%20Framework/" rel="next" title="Spring Framework5.x">
          Spring Framework5.x
          </a>
        
      </div>
  
      <div class="post-nav-item post-nav-prev">
          
          <a href="/2020/07/26/Spring/FactoryBean%E6%8E%A5%E5%8F%A3%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3/" rel="prev" title="FactoryBean接口深入理解">
            FactoryBean接口深入理解
          </a>
          <span>〉</span>
        
      </div>
    </div>
  
  </article>
  <div class="toc-container">
    
  <div id="toc" class="toc-article">
    <strong class="toc-title">目录</strong>
    <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%87%92%E5%8A%A0%E8%BD%BD%E7%9A%84%E5%87%A0%E4%B8%AA%E7%96%91%E9%97%AE%EF%BC%9F%EF%BC%9F"><span class="toc-text">懒加载的几个疑问？？</span></a></li></ol>
  </div>


  </div>
</div>


<div class="copyright">
    <span>本作品采用</span>
    <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by/4.0/">知识共享署名 4.0 国际许可协议</a>
    <span>进行许可。 转载时请注明原文链接。</span>
</div>
<div class="share">

</div>
<div class="post-container">
    <article class="post">
      <div id="container"></div>
    </article>
</div>

<link rel="stylesheet" href="https://imsun.github.io/gitment/style/default.css">
<script src="https://imsun.github.io/gitment/dist/gitment.browser.js"></script>
<script>
var gitment = new Gitment({
  id: '懒加载的几个疑问？？', // 可选。默认为 location.href
  owner: 'ubuntuvim',
  repo: 'ubuntuvim.github.io',
  oauth: {
    client_id: '48b3df0bf4ba1743e0a3',
    client_secret: 'c6c2cec09acb5eecc9d325d56cef187264aa1e16',
  },
})
gitment.render('container')
</script>



    </div>

    

  </div>
  <footer class="footer text-center">
    <div id="bottom-inner">
        <a class="bottom-item" href="http://xcoding.tech/">首页</a> |
        <a class="bottom-item" href="http://xcoding.tech/" target="_blank">主站</a> |
        <a class="bottom-item" href="https://github.com/ubuntuvim" target="_blank">GitHub</a> |
        <a class="bottom-item" href="https://hexo.io" target="_blank">Powered by hexo</a> |
        <a class="bottom-item" href="https://github.com/KevinOfNeu/hexo-theme-xoxo" target="_blank">Theme xoxo</a>
    </div>
</footer>


  <script src='https://unpkg.com/mermaid@7.1.2/dist/mermaid.min.js'></script>
  <script>
    if (window.mermaid) {
      mermaid.initialize({theme: 'forest'});
    }
  </script>


  
  <!-- scripts list from theme config.yml -->
  
    <script src="/js/zepto.min.js"></script>
  


<script>
  (function(window, document, undefined) {

    var timer = null;

    function returnTop() {
      cancelAnimationFrame(timer);
      timer = requestAnimationFrame(function fn() {
        var oTop = document.body.scrollTop || document.documentElement.scrollTop;
        if (oTop > 0) {
          document.body.scrollTop = document.documentElement.scrollTop = oTop - 50;
          timer = requestAnimationFrame(fn);
        } else {
          cancelAnimationFrame(timer);
        }
      });
    }

    var hearts = [];
    window.requestAnimationFrame = (function() {
      return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(callback) {
          setTimeout(callback, 1000 / 60);
        }
    })();
    init();

    function init() {
      css(".heart{z-index:9999;width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: absolute;}.heart:after{top: -5px;}.heart:before{left: -5px;}");
      attachEvent();
      gameloop();
      addMenuEvent();
    }

    function gameloop() {
      for (var i = 0; i < hearts.length; i++) {
        if (hearts[i].alpha <= 0) {
          document.body.removeChild(hearts[i].el);
          hearts.splice(i, 1);
          continue;
        }
        hearts[i].y--;
        hearts[i].scale += 0.004;
        hearts[i].alpha -= 0.013;
        hearts[i].el.style.cssText = "left:" + hearts[i].x + "px;top:" + hearts[i].y + "px;opacity:" + hearts[i].alpha + ";transform:scale(" + hearts[i].scale + "," + hearts[i].scale + ") rotate(45deg);background:" + hearts[i].color;
      }
      requestAnimationFrame(gameloop);
    }

    /**
     * 给logo设置点击事件
     * 
     * - 回到顶部
     * - 出现爱心
     */
    function attachEvent() {
      var old = typeof window.onclick === "function" && window.onclick;
      var logo = document.getElementById("logo");
      if (logo) {
        logo.onclick = function(event) {
          returnTop();
          old && old();
          createHeart(event);
        }
      }
      
    }

    function createHeart(event) {
      var d = document.createElement("div");
      d.className = "heart";
      hearts.push({
        el: d,
        x: event.clientX - 5,
        y: event.clientY - 5,
        scale: 1,
        alpha: 1,
        color: randomColor()
      });
      document.body.appendChild(d);
    }

    function css(css) {
      var style = document.createElement("style");
      style.type = "text/css";
      try {
        style.appendChild(document.createTextNode(css));
      } catch (ex) {
        style.styleSheet.cssText = css;
      }
      document.getElementsByTagName('head')[0].appendChild(style);
    }

    function randomColor() {
      // return "rgb(" + (~~(Math.random() * 255)) + "," + (~~(Math.random() * 255)) + "," + (~~(Math.random() * 255)) + ")";
      return "#F44336";
    }

    function addMenuEvent() {
      var menu = document.getElementById('menu-main-post');
      if (menu) {
        var toc = document.getElementById('toc');
        if (toc) {
          menu.onclick = function() {
            if (toc) {
              if (toc.style.display == 'block') {
                toc.style.display = 'none';
              } else {
                toc.style.display = 'block';
              }
            }
          };
        } else {
          menu.style.display = 'none';
        }
      }
    }

  })(window, document);
</script>

  



</body>
</html>
